package zzzhc.server;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.HashMap;
import java.util.Map;

import javax.imageio.ImageIO;

import zzzhc.image.recognize.ImageRecognizer;
import zzzhc.image.recognize.SerializeUtil;

public class RecognizeServer {

	private String zirPath = "default.zir";

	private ImageRecognizer recognizer;

	private int port = 3210;

	private ServerSocket serverSocket;

	private Thread thread;

	private volatile boolean stop;

	public void start() throws IOException {
		recognizer = SerializeUtil.loadImageRecognizer(new FileInputStream(
				zirPath));
		serverSocket = new ServerSocket(5080, 10);
		thread = new Thread(new Runnable() {

			public void run() {
				while (!stop) {
					try {
						Socket socket = serverSocket.accept();
						new Processor(socket).start();
					} catch (Exception e) {
						e.printStackTrace();
					}
				}
			}

		});
		thread.start();
	}

	public void shutdown() {
		stop = true;
	}

	class Processor extends Thread {

		private Socket socket;

		public Processor(Socket socket) {
			this.socket = socket;
		}

		public void run() {
			try {
				while (true) {
					ByteArrayOutputStream baos = new ByteArrayOutputStream();
					InputStream in = socket.getInputStream();
					byte[] buf = new byte[1024];
					int len = in.read(buf, 0, 20);
					if (len == -1) {
						return;
					}
					int lineEnd = 0;
					int imageLength = 0;
					for (int i = 0; i < len - 1; i++) {
						if (buf[i] == '\r' || buf[i] == '\n') {
							imageLength = Integer
									.parseInt(new String(buf, 0, i));
							if (buf[i + 1] == '\n') {
								lineEnd = i + 2;
							} else {
								lineEnd = i + 1;
							}
							break;
						}
					}
					if (imageLength == 0) {
						System.err.println("invalid image length");
						return;
					}
					baos.write(buf, lineEnd, len - lineEnd);
					while (baos.size() < imageLength) {
						len = in.read(buf);
						if (len == -1) {
							System.err
									.println("invalid request,image data length <"
											+ imageLength);
							return;
						}
						baos.write(buf, 0, len);
					}
					String code = recognizer
							.recognize(ImageIO.read(new ByteArrayInputStream(
									baos.toByteArray())));
					PrintWriter writer = new PrintWriter(socket
							.getOutputStream());
					System.out.println("code=" + code);
					writer.println(code);
					writer.flush();
				}
			} catch (IOException e) {
				e.printStackTrace();
			} finally {
				try {
					socket.close();
				} catch (IOException e) {
				}
			}
		}
	}

	public int getPort() {
		return port;
	}

	public void setPort(int port) {
		this.port = port;
	}

	public String getZirPath() {
		return zirPath;
	}

	public void setZirPath(String zirPath) {
		this.zirPath = zirPath;
	}

	public static void main(String[] args) throws IOException {
		Map<String, String> map = parse(args, new String[] { "z", "p" });
		String zirPath = map.get("z");
		String port = map.get("p");
		if (zirPath == null) {
			zirPath = "default.zir";
		}
		if (port == null) {
			port = "3210";
		}
		RecognizeServer rs = new RecognizeServer();
		rs.setPort(Integer.parseInt(port));
		rs.setZirPath(zirPath);
		rs.start();
		System.out.println("server started...");
	}

	static Map<String, String> parse(String[] args, String[] names) {
		Map<String, String> map = new HashMap<String, String>();
		for (int i = 0; i < args.length - 1; i++) {
			String arg = args[i];
			if (arg.startsWith("-")) {
				String name = arg.substring(1);
				for (String s : names) {
					if (name.equals(s)) {
						String value = args[i + 1];
						map.put(name, value);
						break;
					}
				}
			}
		}
		return map;
	}

}
